// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: declaration of .
//   $Id$



#pragma once
#include "SingleNodeBinding.h"
#include <Common/COM/msw/IDispatchLite.h>

#include <list>
#include "mapBSTRToBSTR.h"

#define min(a,b) (a < b)?a:b
#define max(a,b) (a > b)?a:b
#include "atlutil.h"
#include "IPotentiallyAsynchronousAction.h"
#undef min
#undef max
DWORD WINAPI ThreadRunSubmission(LPVOID vdArg);

class CXFormsParseSubmitInfo;
class CXFormsElementSubmission;
class CXMLRequest;
class CSubmissionExtension;
struct IXmlState;
class CImplContextualValue;
class CImplHeader;
typedef std::list<CImplHeader *> CListOfHeaderObjects;
//typedef std::list<CImplContextualValue*> CContextualValueList;
typedef std::map<CComBSTR, CImplContextualValue*> CMapCComBSTRToContextualValue;

class CImplSubmitInfo 
	: public CImplSingleNodeBinding,
	public IPotentiallyAsynchronousAction
{
	friend class CXFormsParseSubmitInfo;
	friend DWORD WINAPI ThreadRunSubmission(LPVOID vdArg);

public:
	virtual HRESULT doInitialize();
	CImplSubmitInfo(CXFormsElementSubmission * pXFEl);
	virtual ~CImplSubmitInfo();
	//XForms events

	virtual HRESULT onactivate();
	enum ESerialisedLocation
	{
		body,url,header
	};
	
	enum ESerialisation
	{
		xml,nvpair,multipartRelated,multipartForm
	};
	HRESULT RunThreadCompletionRoutineIfReady();
	void AwaitCompletion();
	virtual void getInstanceNode(IXMLDOMNode ** pNode);

private:
	void AddHeader(BSTR sHeaderName,BSTR sValue);
	void AddHeaderExpression(BSTR sHeaderName,BSTR sValue);
	void AddHeaderObject(CImplHeader* pHeader);
	CListOfHeaderObjects m_HeaderObjects;
	CMapCComBSTRToContextualValue m_Headers;
	HRESULT GetHeaders( CSubmissionExtension * pSubExp,CComBSTRMap & mHeaders);
	CComQIPtr<IXMLDOMNode> m_pCurrentNode;
	virtual HRESULT submit();
	ESerialisedLocation m_eSerialisedLocation;
	ESerialisation m_eSerialisation;
	HRESULT replaceAll(CComBSTR sNewDoc);
	CComBSTR m_sAction;
	CComBSTR m_sReplace;
	CComBSTR m_sSeparator;
	CComBSTR m_sReplaceInstance;
	CComBSTR m_sTarget;
	//<xsl:output> attributes
	CComBSTR m_sCDATASectionElements;
	CComBSTR m_sEncoding;
	CComBSTR m_sMediaType;
	CComBSTR m_sMethod;
	CComBSTR m_sOmitXMLDeclaration;
	CComBSTR m_sVersion;
	CComBSTR m_sDoctypePublic;
	CComBSTR m_sDoctypeSystem;
	//Must be BOOL, not bool
	BOOL m_bStandalone;
	BOOL m_bIndent;

	CComBSTR m_sRealMethod;
	
	// XForms 1.1 new submission attributes
	BOOL m_bValidate;
	BOOL m_bRelevant;
	BOOL m_bSerialize;
	BOOL m_bSubmitAsynchronously;

	//Storage for xf:submission/@instance-error
	CComBSTR m_sInstanceError;
	CImplContextualValue * m_pResourceNameResolver;
	CImplContextualValue * m_pVerbResolver;
	CImplContextualValue * m_pMethodResolver;
	void GetVerb(CSubmissionExtension* pSubExt,CComBSTR & sVerb);
	void GetResource(CSubmissionExtension* pSubExt,CComBSTR & sResource);
//	CImplModel* m_pModel;
	
	enum EReplace
	{
		Error = 0,
		None = 1,
		All = 2,
		Instance = 3,
		Text = 4
	}m_eReplaceType;//should have member attached, but it is a string for now (historical reasons).

	bool m_bValidMethod;
	

	HRESULT sendData(BSTR sURL, BSTR sContentType, BSTR sMethod, CComBSTRMap &HeadersList, BSTR sUsername, BSTR sPassword, VARIANT * pvtData, VARIANT * pvtResponse);
	HRESULT filePut(BSTR sURL, VARIANT *pvtBody, const bool bWarn = true);
	HRESULT fileGet(BSTR sURL, VARIANT *pvtResponse, const bool bWarn = true);
//		void CreateElementalRepresentation();
	//so that replace="instance" knows which instance to replace.
	CImplInstance * m_pInstance;
	bool isValid(IXMLDOMNode * pNode);
	
	HRESULT getSerializedData(BSTR * pbsURL, VARIANT * pvtRetVal, BSTR * psContentType, CSubmissionExtension * pSubExt);
	HRESULT serializeURLEncodedForm(IXMLDOMNode * pNode, BSTR * bsAsText,IXmlState * pStateResolver, BSTR * psContentType, CSubmissionExtension * pSubExt) const ;
	HRESULT serializeMultipartRelated(IXMLDOMNode * pNode, VARIANT * pvtData,IXmlState * pStateResolver, BSTR * psContentType, CSubmissionExtension * pSubExt) const;
	HRESULT serializeMultipartForm(IXMLDOMNode * pNode, VARIANT * pvtData,IXmlState * pStateResolver, BSTR * psContentType, CSubmissionExtension * pSubExt) const ;
	HRESULT serializeXML(IXMLDOMNode * pNode , VARIANT * pvtData,IXmlState * pStateResolver, BSTR * psContentType, CSubmissionExtension * pSubExt);
	HRESULT serializeByXSLT(char * bsXSLName, IXMLDOMNode * pNode , VARIANT * pvtData,IXmlState * pStateResolver, CSubmissionExtension * pSubExt) const ;

	HRESULT BinaryFromVariant(BYTE ** ppBytes, ULONG * pulBuffSize, VARIANT * pvtData);
	HRESULT BinaryFromIStream(BYTE ** ppBytes, ULONG * pulBuffSize, IStream * pStream);


	//submit methods.
	HRESULT httpGET(BSTR sURL, VARIANT * pvtResponse);
	
	IXMLDOMElement * m_pElementalRepresentation;

	
	HRESULT getResponse(BSTR * psQueryString, VARIANT * pvtData, BSTR * psContentType, VARIANT * pvtResponse,bool * pbReplaceAfter, CSubmissionExtension * pSubExt);
	HRESULT	replaceData(VARIANT const vtResponseData);

	HRESULT getIStream(IStream ** pStream) const;
	HRESULT getSubmissionExtensionElement(IXMLDOMNode ** pExtNode);
	HRESULT getSubmissionExtension(CSubmissionExtension ** ppSubExt);
	HRESULT AddExtensionHeaders(CComBSTR &sHeaders, CSubmissionExtension * pSubExp);
	bool isProtocol(wchar_t * pszURL, wchar_t * pszProtocol);
	

	bool m_bLastResponseSuccessful;
	bool m_bShouldDataBeReplaced;

	HRESULT OnSubmissionResponseReceived(VARIANT vtResponseData);
	HRESULT OnSubmissionResponseReceived();
	void StoreResponse(CComVariant * vtResponseData,bool bSuccess,bool bShouldDataBeReplaced);
	CComPtr<IDispatch> m_pDataReadyHandler;
	CRITICAL_SECTION m_RunningCritsec;
	bool EnterActivatedSection();
	void LeaveActivatedSection();
	//If instance-error has been specified, store the result in the appropriate instance
	HRESULT StoreErroneousResponse(CComVariant & vtData);
	class CSubmissionCallback
		:public CIDispatchLite
	{
		public:
			
			static CSubmissionCallback * CreateSubmissionCallback(CImplSubmitInfo * pSubmission)
			{
				CSubmissionCallback * pNew = new CSubmissionCallback();
				pNew->m_pSubmission = pSubmission;
				
				return pNew;
			};
		STDMETHODIMP Invoke(DISPID dispidMember, REFIID  /*riid*/, LCID /*lcid*/, WORD /*wFlags*/,
			DISPPARAMS* /*pdispparams*/, VARIANT* /*pvarResult*/, EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/)
		{
			HRESULT hr = E_NOTIMPL;
			if(DISPID_VALUE == dispidMember && m_pSubmission)
			{
				hr = m_pSubmission->OnSubmissionResponseReceived();
			}
			else if(1 == dispidMember)
			{

				m_pSubmission = 0;
				hr = S_OK;
			}
			return hr;
		}

		private:
			CImplSubmitInfo * m_pSubmission;
	};
	friend class CSubmissionCallback;

	CXMLRequest * m_req;
public:
	virtual HRESULT init(CImpl * pParent);
	// Add for Bug 348
	HRESULT initMethod(void);
private:
	void SetStateResolverParameters(IXmlState* pState);
	HRESULT InnerGetSerializedData(BSTR * pbsURL, BSTR * psContentType,IXmlState* pState,IXMLDOMNode * pNode, CSubmissionExtension * pSubExt,VARIANT * pvtRetVal);
	void ResolveReplace();
	// HACK: Temporary addition to work round a specific problem in Hubbub.
	bool m_bAuthenticate;
	HRESULT wininetGet(BSTR sURL, CComBSTRMap &mapHeaders, VARIANT vData, VARIANT *pvResponse);
};
